package common

import (
	"context"
	"errors"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

// Run 公共的run方法,哪个服务需要启动,就传入*gin.Engine,直接调用该公共模块的这个方法,即可
func Run(r *gin.Engine, srvName string, addr string, stop func()) {
	srv := &http.Server{
		Addr:    addr,
		Handler: r,
	}

	//保证下面的优雅启停
	go func() {
		log.Printf("%s web server running in %s \n", srvName, srv.Addr)
		if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			log.Fatalln(err)
		}
	}()

	quit := make(chan os.Signal)
	//SIGINT 用户发送INTR字符(Ctrl+C)触发
	//SIGTERM 结束程序(可以被捕获、阻塞或忽略)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit //主线程在这里阻塞, 一直等待程序关闭的信号
	log.Printf("Shutting Down project web server %s... \n", srvName)

	//创建一个5秒超时的上下文对象
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	//关闭管道接听到关闭服务的消息, 直接stop关闭方法
	if stop != nil {
		stop()
	}

	if err := srv.Shutdown(ctx); err != nil { //关闭方法如果出错, 打印出来
		log.Fatalf("%s web server Shutdown, cause by : %v", srvName, err)
	}

	select {
	case <-ctx.Done(): //ctx.Done(): 如果该请求确实超时,那么进行取消, 然后向固定管道中发送消息,ctx.Done()就是获取这个超时消息
		log.Println("关闭超时")
	}
	log.Printf("%s server stop success... \n", srvName)
}
